Billboard Top 100 Song Length Over Time
library(ggplot2)
library(plotly)
library(dplyr)
# Your ggplot base
plot <- spotify_cleaned_all %>%
filter(duration_sec <= 600, date>= '1958-08-06') %>%
ggplot(aes(
x = as.Date(date),
y = duration_sec,
text = paste0(
"Song: ", song, "<br>",
"Artist: ", artist, "<br>",
"Date: ", date, "<br>",
"Duration: ", duration_min
),
group = 1
)) +
geom_jitter(color = "darkgreen", size = 1.5, alpha = 0.4, width = 10) +
geom_smooth(method = "gam", color = "darkblue", se = FALSE, linewidth = 1.2) +
scale_y_continuous(
name = "Song Duration",
breaks = seq(0, 600, by = 60),
labels = function(x) sprintf("%d:%02d", floor(x / 60), round(x %% 60))
) +
labs(
title = "Billboard Hot 100 Top 10 Song Durations Over Time",
x = "Chart Date"
) +
theme_minimal()
p <- ggplotly(plot + labs(title = NULL), tooltip = "text") # remove ggplot title
## Warning: The following aesthetics were dropped during statistical transformation: text
## ℹ This can happen when ggplot fails to infer the correct grouping structure in
## the data.
## ℹ Did you forget to specify a `group` aesthetic or to convert a numerical
## variable into a factor?
p <- layout(p,
title = NULL, # make sure nothing else forces the title
images = list(
list(
source = billboard_b64,
xref = "paper", yref = "paper",
x = 0.7, y = 1.04,
sizex = 0.12, sizey = 0.12,
xanchor = "left", yanchor = "top"
),
list(
source = spotify_b64,
xref = "paper", yref = "paper",
x = 0.85, y = 1.05,
sizex = 0.12, sizey = 0.12,
xanchor = "left", yanchor = "top"
)
),
annotations = list(
list( # Title text aligned with logos
text = "<b>Billboard Hot 100 Top 10 Song Durations Over Time</b>",
x = 0.34, y = 1.045,
xref = "paper", yref = "paper",
xanchor = "center", yanchor = "top",
showarrow = FALSE,
font = list(size = 16, color = "black")
),
list( # Data source footnote
text = "Data sources: Spotify Web API & Billboard Hot 100",
x = 0.05, y = 0.01,
xref = "paper", yref = "paper",
xanchor = "left", yanchor = "bottom",
showarrow = FALSE,
font = list(size = 10, color = "gray40")
)
),
margin = list(t = 100) # top margin to fit title
)
p